home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
FTPSERV.C
< prev
next >
Wrap
Text File
|
1993-08-09
|
12KB
|
476 lines
/* FTP Server state machine - see RFC 959 */
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#ifdef __TURBOC__
#include <io.h>
#include <dir.h>
#endif
#include "global.h"
#include "mbuf.h"
#include "dirutil.h"
#include "files.h"
#include "ftp.h"
#include "server.h"
/* Response messages */
static char binwarn[] = "100 Warning: type is ASCII and '%s' appears to be binary\n";
static char sending[] = "150 Opening data connection for %s %s\n";
static char okay[] = "200 %s command OK\n";
static char banner[] = "220 %s FTP %s ready at %s";
static char bye[] = "221 Goodbye!\n";
static char fileok[] = "226 File %s OK\n";
static char logged[] = "230 Logged in\n";
static char deleok[] = "250 File '%s' deleted\n";
static char pwdmsg[] = "257 '%s' is current directory\n";
static char givepass[] = "331 Enter PASS command\n";
static char noconn[] = "425 Data connection reset\n";
static char badcmd[] = "500 Unknown command\n";
static char badsyntax[] = "500 Syntax error\n";
static char unsupp[] = "500 Unsupported command or option\n";
static char only8[] = "501 Only logical bytesize 8 supported\n";
static char badtype[] = "501 Unknown type %s\n";
static char badport[] = "501 Bad port syntax\n";
/*
static char unimp[] = "502 Command not yet implemented\n";
*/
static char userfirst[] = "503 Login with USER first.\n";
static char notlog[] = "530 Please log in with USER and PASS\n";
static char delefail[] = "550 Can't delete %s: %s\n";
static char writerr[] = "552 Can't write %s: %s\n";
static char nodir[] = "553 Can't read %s: %s\n";
static char cantmake[] = "553 Can't create %s: %s\n";
static char nopos[] = "554 Can't position %s\n";
static char noperm[] = "550 Permission denied\n";
static void near
close_ftpconn(struct ftpserv *ftp)
{
if(ftp->fp != NULLFILE) {
Fclose(ftp->fp);
}
ftp->fp = NULLFILE;
if(ftp->data != -1) {
close_s(ftp->data);
}
ftp->data = -1;
}
static int near
setup_ftpconn(struct ftpserv *ftp,char *command)
{
struct sockaddr_in dport;
usprintf(ftp->control,sending,command,ftp->line);
ftp->data = socket(AF_INET,SOCK_STREAM,0);
dport.sin_family = AF_INET;
dport.sin_addr.s_addr = INADDR_ANY;
dport.sin_port = IPPORT_FTPD;
bind(ftp->data,(char *)&dport,SOCKSIZE);
if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1) {
usputs(ftp->control,noconn);
return -1;
}
return 0;
}
static void near
sendit(struct ftpserv *ftp,char *command,int32 offset)
{
if(setup_ftpconn(ftp,command) != -1) {
if(fseek(ftp->fp,offset,SEEK_SET)) { /* restart dk5dc */
usprintf(ftp->control,nopos,ftp->line);
close_ftpconn(ftp);
return;
}
if(sendfile(ftp->fp,ftp->data,ftp->type,0) == -1) {
/* An error occurred on the data connection */
ftp->states = CLOSED;
usputs(ftp->control,noconn);
shutdown(ftp->data,2); /* Blow away data connection */
ftp->data = -1;
} else {
usprintf(ftp->control,fileok,"sent");
}
}
close_ftpconn(ftp);
}
/*-------------------------- FTP Server subcmd -----------------------------*/
static void near
cwd_command(struct ftpserv *ftp)
{
if(access(ftp->line,0) == 0) {
/* Succeeded, record in control block */
xfree(ftp->cd);
ftp->cd = strxdup(ftp->line);
usprintf(ftp->control,pwdmsg,ftp->cd);
} else {
/* Failed, don't change anything */
usprintf(ftp->control,nodir,ftp->line,sys_errlist[errno]);
}
}
static void near
dele_command(struct ftpserv *ftp)
{
if(unlink(ftp->line) == 0) {
usprintf(ftp->control,deleok,ftp->line);
} else {
usprintf(ftp->control,delefail,ftp->line,sys_errlist[errno]);
}
}
static void near
dir_command(struct ftpserv *ftp)
{
if((ftp->fp = dir(ftp->line,1)) == NULLFILE) {
usprintf(ftp->control,nodir,ftp->line,sys_errlist[errno]);
} else {
sendit(ftp,"LIST",0);
}
}
static void near
mkd_command(struct ftpserv *ftp)
{
if(mkdir(ftp->line) == 0) {
usprintf(ftp->control,okay,"MKD");
} else {
usprintf(ftp->control,cantmake,ftp->line,sys_errlist[errno]);
}
}
static void near
nlst_command(struct ftpserv *ftp)
{
if((ftp->fp = dir(ftp->line,0)) == NULLFILE) {
usprintf(ftp->control,nodir,ftp->line,sys_errlist[errno]);
} else {
sendit(ftp,"NLST",0);
}
}
static void near
pass_command(struct ftpserv *ftp)
{
if(ftp->username == NULLCHAR) {
usputs(ftp->control,userfirst);
} else {
if(userlogin(IPPORT_FTP,(void *)ftp,ftp->line) > 0) {
ftp->cd = strxdup(ftp->path);
}
ftp->states = LOG;
log(ftp->control,9983,"FTP open %s %s",
ftp->username,ftp->perms ? "" : ftp->line);
usputs(ftp->control,ftp->perms ? logged : noperm);
}
}
static void near
port_command(struct ftpserv *ftp)
{
int i;
int32 n;
char *arg = ftp->line;
struct sockaddr_in *sock = &ftp->port;
sock->sin_port = 0;
for(i = 0, n = 0; i < 4; i++) {
n = atoi(arg) + (n << 8);
if((arg = strchr(arg,',')) == NULLCHAR) {
goto error;
}
arg++;
}
sock->sin_addr.s_addr = n;
n = atoi(arg);
if((arg = strchr(arg,',')) != NULLCHAR) {
arg++;
n = atoi(arg) + (n << 8);
sock->sin_port = n;
usprintf(ftp->control,okay,"PORT");
return;
}
error:
usputs(ftp->control,badport);
}
static void near
pwd_command(struct ftpserv *ftp)
{
usprintf(ftp->control,pwdmsg,ftp->cd);
}
static void near
quit_command(struct ftpserv *ftp)
{
usputs(ftp->control,bye);
ftp->states = CLOSED;
}
static void near
retr_command(struct ftpserv *ftp)
{
if((ftp->fp = Fopen(ftp->line,
(ftp->type == ASCII_TYPE) ? READ_TEXT : READ_BINARY,ftp->control,0)) != NULLFILE) {
if(ftp->type == ASCII_TYPE && isbinary(ftp->fp)) {
usprintf(ftp->control,binwarn,ftp->line);
}
sendit(ftp,"RETR",0);
}
}
static void near
rmd_command(struct ftpserv *ftp)
{
if(rmdir(ftp->line) == 0) {
usprintf(ftp->control,deleok,ftp->line);
} else {
usprintf(ftp->control,delefail,ftp->line,sys_errlist[errno]);
}
}
static void near
srest_command(struct ftpserv *ftp)
{
char *cp;
/*---------------------------------------------------------------*
* Restart request comes in at this point. Try to find 'remote- *
* file, check offset. *
* refuse if pass EOF else advance and initiate transfer *
*---------------------------------------------------------------*/
if((cp = strchr(ftp->line,' ')) != NULLCHAR) {
int32 restpos = atol(cp);
*cp = '\0';
if((ftp->fp = Fopen(ftp->line,
(ftp->type == ASCII_TYPE) ? READ_TEXT : READ_BINARY,ftp->control,0)) != NULLFILE) {
if(ftp->type == ASCII_TYPE && isbinary(ftp->fp)) {
usprintf(ftp->control,binwarn,ftp->line);
}
sendit(ftp,"SREST",restpos);
}
} else {
usputs(ftp->control,badsyntax);
}
}
static void near
stor_command(struct ftpserv *ftp)
{
if((ftp->fp = Fopen(ftp->line,
(ftp->type == ASCII_TYPE) ? WRITE_TEXT : WRITE_BINARY,ftp->control,1)) != NULLFILE) {
if(setup_ftpconn(ftp,"STOR") != -1) {
if(recvfile(ftp->fp,ftp->data,ftp->type,0) == -1) {
/* An error occurred while writing the file */
ftp->states = CLOSED;
usprintf(ftp->control,errno ? writerr : noconn,ftp->line,sys_errlist[errno]);
shutdown(ftp->data,2); /* Blow away data connection */
ftp->data = -1;
} else {
usprintf(ftp->control,fileok,"received");
}
}
close_ftpconn(ftp);
}
}
static void near
type_command(struct ftpserv *ftp)
{
int ok = TRUE;
char *cp = ftp->line;
switch(tolower(*cp)) {
case 'a': /* Ascii */
ftp->type = ASCII_TYPE;
break;
case 'l':
while(!isspace(*cp++)) ;
if(*cp != '8') {
usputs(ftp->control,only8);
return;
}
ftp->type = LOGICAL_TYPE;
ftp->logbsize = 8;
break;
case 'b': /* Binary */
case 'i': /* Image */
ftp->type = IMAGE_TYPE;
break;
default: /* Invalid */
ok = FALSE;
break;
}
if(ok)
usprintf(ftp->control,okay,"TYPE");
else
usprintf(ftp->control,badtype,strupr(cp));
}
static void near
unsupp_command(struct ftpserv *ftp)
{
usputs(ftp->control,unsupp);
}
static void near
user_command(struct ftpserv *ftp)
{
if(ftp->username != NULLCHAR)
xfree(ftp->username);
ftp->username = strxdup(ftp->line);
ftp->states = PASS;
usputs(ftp->control,givepass);
}
void
ftpserv(int s,void *unused,void *p)
{
/* Command table */
static struct cmdtable {
char *name;
void near (*fnc)(struct ftpserv *ftp);
int states;
int perms;
} cmdtable[] = {
{"ACCT", unsupp_command, LOG, 0},
{"CWD", cwd_command, LOG, RETR_CMD},
{"DELE", dele_command, LOG, DELE_CMD},
{"HELP", unsupp_command, LOG, 0},
{"LIST", dir_command, LOG, RETR_CMD},
{"MKD", mkd_command, LOG, MKD_CMD},
{"MODE", unsupp_command, LOG, 0},
{"NLST", nlst_command, LOG, RETR_CMD},
{"PASS", pass_command, PASS, 0},
{"PORT", port_command, LOG, 0},
{"PWD", pwd_command, LOG, 0},
{"QUIT", quit_command, USER, 0},
{"RETR", retr_command, LOG, RETR_CMD},
{"RMD", rmd_command, LOG, RMD_CMD},
{"SREST", srest_command, LOG, RETR_CMD},
{"STOR", stor_command, LOG, STOR_CMD},
{"STRU", unsupp_command, LOG, 0},
{"TYPE", type_command, LOG, 0},
{"USER", user_command, USER, 0},
/* For compatibility with 4.2BSD */
{"XMKD", mkd_command, LOG, MKD_CMD},
{"XPWD", pwd_command, LOG, 0},
{"XRMD", rmd_command, LOG, RMD_CMD},
{0, 0, 0, 0}
} ;
struct cmdtable *cmdp;
char *cp, *cp1;
int arglen, i = SOCKSIZE;
struct sockaddr_in socket;
struct ftpserv *ftp;
sockowner(s,Curproc); /* We own it now */
sockmode(s,SOCK_ASCII);
usprintf(s,banner,Hostname,Version,ctime(&currtime));
ftp = mxallocw(sizeof(struct ftpserv));
ftp->line = mxallocw(FTPLINE);
ftp->data = -1;
ftp->control = s;
ftp->type = ASCII_TYPE;
/* Set default data port */
getpeername(ftp->control,(char *)&socket,&i);
socket.sin_port = IPPORT_FTPD;
ASSIGN(ftp->port,socket);
for( ; ;) {
loop:
if(ftp->states == CLOSED)
break;
if(recvline(ftp->control,ftp->line,FTPLINE) <= 0) {
/* He closed on us */
break;
}
rip(ftp->line);
arglen = 0;
cp = ftp->line;
while(isspace(*cp))
cp++;
cp1 = cp;
while(*cp1 != '\0' && !isspace(*cp1)) {
cp1++;
arglen++;
}
if(arglen) {
for(cmdp = cmdtable; cmdp->name; cmdp++) {
if(strnicmp(cmdp->name,cp,arglen) == 0) {
char *file, *cp2 = cp1;
if(cmdp->fnc != port_command) {
log(ftp->control,IPPORT_FTP,ftp->line); /* TEST */
}
if(ftp->states < cmdp->states) {
usputs(ftp->control,notlog);
goto loop;
}
while(isspace(*cp2)) {
cp2++;
}
if(cmdp->perms) {
file = pathname(ftp->cd,cp2);
if(!permcheck(ftp->path,ftp->perms,cmdp->perms,file)) {
usputs(ftp->control,noperm);
xfree(file);
goto loop;
}
} else {
file = strxdup(cp2);
}
strcpy(ftp->line,file);
xfree(file);
(*cmdp->fnc)(ftp);
goto loop;
}
}
}
/* Can't be a legal FTP command */
usputs(ftp->control,badcmd);
}
log(ftp->control,9983,"FTP close");
/* Clean up */
close_ftpconn(ftp);
close_s(ftp->control);
if(ftp->path != NULLCHAR)
xfree(ftp->path);
if(ftp->cd != NULLCHAR)
xfree(ftp->cd);
xfree(ftp->username);
xfree(ftp->line);
xfree(ftp);
}